import 'dart:async';
import 'dart:collection';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_scan_tool/db/sp_provider.dart';
import 'package:flutter_scan_tool/models/antenna.dart';
import 'package:flutter_scan_tool/models/socket_message.dart';
import 'package:flutter_scan_tool/models/socket_message_tool.dart';
import 'package:flutter_scan_tool/models/storage_info.dart';
import 'package:flutter_scan_tool/models/temp_humidyty.dart';
import 'package:flutter_scan_tool/models/tool_kit.dart';
import 'package:flutter_tool/flutter_tool.dart';
import 'package:web_socket_channel/io.dart';

import '../../models/reader_event.dart';

part 'device_event.dart';

part 'device_state.dart';

enum ResultType { unknow, start, finish, unfinish }

class DeviceBloc extends Bloc<DeviceEvent, DeviceState> {
  late FlutterTool flutterTool;
  IOWebSocketChannel? channel;
  SpProvider? sp;
  StorageInfo? storageInfo;
  bool storageIsConfig = false;
  Timer? timer;
  Timer? countTimer;
  int count = 0;
  int gpo = 0;
  int gpi = 0;
  bool gpiLevel = false;
  bool readyToScan = false;
  String? toolKitName = '';
  int stockType = 0;
  ResultType resultType = ResultType.unknow;
  bool epcRead = false;

  DeviceBloc() : super(const DeviceState()) {
    flutterTool = FlutterTool(_eventListener);
    on<DeviceVersionEvent>((event, emit) async {
      flutterTool.getPlatformVersion();
    });
    on<DeviceConnectEvent>((event, emit) async {
      try {
        emit(state.copyWith(isStorageConfig: StorageStatus.inital));
        sp = SpProvider.spProvider;
        String storageStr = await sp!.getValue('storage');
        if (storageStr.isNotEmpty) {
          storageInfo = StorageInfo.fromJson(storageStr);
          storageIsConfig = true;
          emit(state.copyWith(
            storageId: storageInfo?.id,
            storageName: storageInfo?.storageName,
            isStorageConfig: StorageStatus.config,
          ));
          startWebSocket();
        } else {
          emit(state.copyWith(
            isStorageConfig: StorageStatus.unConfig,
            storageName: '请配置仓库信息',
            socketConnectStatus: ConnectStatus.disConnected,
          ));
        }

        String? res = await flutterTool.readerConnection();
        debugPrint(res.toString());
        if (res != null && res.isNotEmpty) {
          List<AntennaData> list = [];
          // for (int i = 0; i < res.length; i++) {
          //   var item = Map<String, dynamic>.from(res[i]);
          //   AntennaData antennaData = AntennaData.fromMap(item);
          //   list.add(antennaData);
          // }
          emit(state.copyWith(
              isConnect: ConnectStatus.connected, antennaList: list));
        } else {
          emit(state.copyWith(isConnect: ConnectStatus.disConnected));
        }
      } catch (err) {
        emit(state.copyWith(isConnect: ConnectStatus.disConnected));
      }
    });
    on<DeviceDisconnectEvent>((event, emit) async {
      String? res = await flutterTool.readerDisconnection();
      emit(state.copyWith(isConnect: ConnectStatus.disConnected));
    });
    on<DeviceStorageEvent>((event, emit) {
      storageInfo = event.storageInfo;
      storageIsConfig = true;
      startWebSocket();
      emit(state.copyWith(
          isStorageConfig: StorageStatus.config,
          storageId: storageInfo?.id,
          storageName: storageInfo?.storageName));
    });
    on<DeviceConfigUpdateEvent>((event, emit) async {
      if (state.isConnect == ConnectStatus.connected) {
        List<int> list = event.antenaData.map((e) => e.powerValue).toList();
        String? res = await flutterTool.updateAntennaInfo(list);
        if (res.isNotEmpty) {
          emit(state.copyWith(antennaList: event.antenaData));
        }
      }
    });
    on<DeviceFetchCompleteEvent>((event, emit) {
      if (channel != null) {
        closeDoor();
      }
    });
    on<DeviceSocketEvent>((event, emit) {
      emit(state.copyWith(socketConnectStatus: event.connectStatus));
    });
    on<DeviceResetReadingStatusEvent>((event, emit) {
      emit(state.copyWith(
          message: event.message,
          readFinish: event.readFinish,
          isReading: event.isReading,
          showForceOperationButton: event.showForceOperationButton,
          collectList: event.collectList,
          handleList: event.handleList,
          operateType: event.operationType,
          toolKitId: event.toolKitId));
    });
    on<DeviceReadingEpcEvent>((event, emit) {
      emit(state.copyWith(collectList: event.epcList));
    });
    on<DeviceReadingStatusChangeEvent>((event, emit) {
      emit(state.copyWith(
          isReading: event.isReading, readFinish: event.readFinish));
      SocketMessageTool messageTool = SocketMessageTool(
          epcList: state.collectList,
          toolKitId: state.toolKitId,
          storageId: state.storageId,
          stockType: stockType);
      SocketMessageInfo messageInfo =
          SocketMessageInfo(data: messageTool.toJson(), messageType: "11");
      sp!.setStringList(state.toolKitId, state.collectList);
      channel!.sink.add(messageInfo.toJson());
    });
    on<DeviceNoticeEvent>((event, emit) {
      emit(state.copyWith(notice: event.notice));
    });
    on<DeviceTemperatureEvent>((event, emit) {
      emit(state.copyWith(
          temperature: event.indoorTemperature.toString(),
          humidity: event.indoorHumidity.toString(),
          heatStatus: event.heatStatus,
          dehumidifyStatus: event.dehumidifyStatus,
          exhaustStatus: event.exhaustStatus,
          airConStatus: event.airConStatus,
          autoStatus: event.autoStatus,
          alarmStatus: event.alarmStatus,
          airCleanStatus: event.airCleanStatus));
    });
  }

  void closeDoor() async {
    bool res = await flutterTool.closeDoor(gpi);
    if (res) {
      add(DeviceNoticeEvent('门锁关闭已启动'));
      readyToScan = true;
      if (gpiLevel) {
        readyToScan = false;
        startWork();
      }
    } else {
      add(DeviceNoticeEvent('门锁关闭无法启动'));
    }
  }

  bool isReconnect = false;

  void startWebSocket() {
    if (timer != null) {
      timer?.cancel();
      isReconnect = true;
      channel?.sink.close();
      timer = null;
    }
    String storageId = storageInfo!.id;
    List<String> toolKitNameList =
        storageInfo!.toolKitList?.map((ele) => ele.id).toList() ?? [];
    String toolKitNames = toolKitNameList.join(',');
    String urlStr =
        'ws://localhost:8083?storageId=$storageId&&toolKitId=$toolKitNames';
    try {
      channel = IOWebSocketChannel.connect(urlStr);
      isReconnect = false;
      channel!.stream.listen((event) {
        _receivedData(event);
      }, onDone: () {
        debugPrint("socket is closed");
        add(DeviceSocketEvent(ConnectStatus.disConnected));
        if (!isReconnect) {
          _restartSocket();
        }
      }, onError: (err) {
        add(DeviceSocketEvent(ConnectStatus.disConnected));
      });
      timer = Timer.periodic(const Duration(seconds: 20), (timer) {
        if (channel?.closeCode != null) {
          _restartSocket();
        } else {
          channel?.sink.add('{messageType:0}');
        }
      });
    } catch (err) {
      add(DeviceSocketEvent(ConnectStatus.disConnected));
      _restartSocket();
    }
  }

  void _receivedData(dynamic event) async {
    debugPrint("response socket info:${event.toString()}");
    var info = SocketMessageInfo.fromJson(event);
    if (state.socketConnectStatus != ConnectStatus.connected) {
      add(DeviceSocketEvent(ConnectStatus.connected));
    }
    switch (info.messageType) {
      case "0":
        break;
      case "15":
        TempHumidity tempHumidity = TempHumidity.fromJson(info.data);
        add(DeviceTemperatureEvent(
            tempHumidity.indoorTemperature,
            tempHumidity.indoorHumidity,
            tempHumidity.heatStatus,
            tempHumidity.dehumidifyStatus,
            tempHumidity.exhaustStatus,
            tempHumidity.airConStatus,
            tempHumidity.autoStatus,
            tempHumidity.alarmStatus,
            tempHumidity.airCleanStatus));
        break;
      case "10":
        SocketMessageTool toolMessage = SocketMessageTool.fromJson(info.data);
        resultType = ResultType.start;
        List<String>? valueList =
            await sp!.getStringList(toolMessage.toolKitId);
        List<String> errList = [];
        if (valueList.isNotEmpty) {
          if (toolMessage.stockType > 0) {
            for (var item in toolMessage.epcList) {
              if (!valueList.contains(item)) {
                errList.add(item);
              }
            }
          } else {
            for (var item in toolMessage.epcList) {
              if (valueList.contains(item)) {
                errList.add(item);
              }
            }
          }
        }
        if (storageInfo != null) {
          List<ToolKit> toolKitList = storageInfo?.toolKitList ?? [];
          ToolKit toolKit = toolKitList
              .where((element) => element.id == toolMessage.toolKitId)
              .first;
          gpo = toolKit.gpo;
          gpi = toolKit.gpi;
          toolKitName = toolKit.toolKitName;
        }
        stockType = toolMessage.stockType;
        debugPrint('socket send to info:${errList.toString()}');
        add(DeviceResetReadingStatusEvent(
            message: errList.isNotEmpty ? '${errList.toString()}未能进行当前操作' : '',
            readFinish: false,
            isReading: true,
            operationType: stockType,
            showForceOperationButton: false,
            collectList: const <String>[],
            handleList: toolMessage.epcList,
            toolKitId: toolMessage.toolKitId));
        bool res = await flutterTool.openDoor(gpi);
        if (res) {
          readyToScan = false;
          add(DeviceNoticeEvent('门锁已打开'));
        } else {
          add(DeviceNoticeEvent('门锁打开失败,无法继续执行操作'));
        }

        break;
      default:
        break;
    }
  }

  void _restartSocket() {
    startWebSocket();
  }

  void startWork() {
    debugPrint('当前开始时间:${DateTime.now().toString()}');
    if (state.storageId == storageInfo!.id) {
      if (state.toolKitId.isNotEmpty) {
        ToolKit toolKit = storageInfo!.toolKitList!
            .firstWhere((element) => element.id == state.toolKitId);
        List<String> portList =
            toolKit.antennaList.map((e) => e.antennaPort).toList();
        count = 0;
        epcRead = false;
        flutterTool.startReading(portList);
        Future.delayed(const Duration(seconds: 2), noResponseCallBack);
      }
    }
  }

  void noResponseCallBack() {
    if (!epcRead) {
      flutterTool.stopReading();
      add(DeviceReadingStatusChangeEvent(false, true));
    }
  }

  void _eventListener(dynamic event) {
    HashMap<String, dynamic> maps = HashMap.from(event);
    ReaderEvent readerEvent = ReaderEvent.fromJson(maps);
    if (readerEvent.type!.isNotEmpty) {
      if ('1' == readerEvent.type) {
        debugPrint(readerEvent.level);
        if (readerEvent.level == '0') {
          gpiLevel = false;
          flutterTool.clearEpcList();
          // add(DeviceButtonStatusEvent(false));
        }
        if (readerEvent.level == '1') {
          gpiLevel = true;
          if (readyToScan) {
            readyToScan = false;
            startWork();
          }
        }
      }
      if ('2' == readerEvent.type) {
        debugPrint(readerEvent.toString());
        epcRead = true;
        int countTime = 0;
        if (countTimer != null) {
          countTimer?.cancel();
          countTimer = null;
        }
        countTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
          if (readerEvent.epcList?.length != count) {
            count = readerEvent.epcList!.length;
          } else {
            if (countTime == 0) {
              countTime++;
            } else {
              bool isContains = false;
              if (state.operateType == 0) {
                for (var item in state.handleList) {
                  if (!state.collectList.contains(item)) {
                    isContains = false;
                    break;
                  } else {
                    isContains = true;
                  }
                }
                if (isContains) {
                  resultType = ResultType.finish;
                }
              }
              if (state.operateType > 0) {
                for (var item in state.handleList) {
                  if (state.collectList.contains(item)) {
                    isContains = false;
                    break;
                  } else {
                    isContains = true;
                  }
                }
                if (isContains) {
                  resultType = ResultType.finish;
                }
              }
              sendToServerToolResult();
              flutterTool.stopReading();
              countTimer?.cancel();
              countTimer = null;
              countTime = 0;
            }
          }
        });
        add(DeviceReadingEpcEvent(readerEvent.epcList!));
      }
    }
  }

  void sendToServerToolResult() {
    add(DeviceReadingStatusChangeEvent(false, true));
  }
}
